#include "SD.h"
#include "esp_camera.h"
#include "FS.h"
#include <SPI.h>
#include <SD.h>
#include "SD_MMC.h"
#include <time.h> 
#include "string.h"
#include <HTTPClient.h>
#include <WiFi.h>
#include <ArduinoJson.h>

/*********************需要修改的地方**********************/
const char* ssid = "xuanWiFi";           //WIFI名称
const char* password = "asdfghjk";     //WIFI密码
int capture_interval = 5*1000;     
const char*  post_url = "http://images.bemfa.com/upload/v1/upimages.php"; 
const char*  uid = "af5f58e847008d7b19221a66b7af3a53";    
const char*  topic = "ESP32CAM";     
bool sentWechat = true;              
const char*  wechatMsg = "自定义消息，哈哈，就是图片，点击可以查看";     
char path[] = "/2020_6_18_TIME_19_0_47.jpg";
int num=0;
/********************************************************/


bool internet_connected = false;
long current_millis;
long last_capture_millis = 0;

// CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM      0
#define SIOD_GPIO_NUM     26
#define SIOC_GPIO_NUM     27
#define Y9_GPIO_NUM       35
#define Y8_GPIO_NUM       34
#define Y7_GPIO_NUM       39
#define Y6_GPIO_NUM       36
#define Y5_GPIO_NUM       21
#define Y4_GPIO_NUM       19
#define Y3_GPIO_NUM       18
#define Y2_GPIO_NUM        5
#define VSYNC_GPIO_NUM    25
#define HREF_GPIO_NUM     23
#define PCLK_GPIO_NUM     22





void sd_init()
{
  if(!SD_MMC.begin()){
    Serial.println("Card Mount Failed");
    return;
  }
  uint8_t cardType = SD_MMC.cardType();
  if(cardType == CARD_NONE){
    Serial.println("No SD card attached");
    return;
  }
  Serial.print("SD Card Type: ");
  if(cardType == CARD_MMC){
    Serial.println("MMC");
    } 
  else if(cardType == CARD_SD){  Serial.println("SDSC");  }
  else if(cardType == CARD_SDHC){  Serial.println("SDHC");  } 
  else {  Serial.println("UNKNOWN");  }
  
  uint64_t cardSize = SD_MMC.cardSize() / (1024 * 1024);    //获取SD卡大小，大小单位是MB
  Serial.printf("SD 卡容量大小: %lluMB\n", cardSize);  
  }

/********初始化WIFI*********/
bool init_wifi()
{
  int connAttempts = 0;
  Serial.println("\r\nConnecting to: " + String(ssid));
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED ) {
    delay(500);
    Serial.print(".");
    if (connAttempts > 10) return false;
    connAttempts++;
  }
  return true;
}


void num_to_str(int num , char str[])
{ memset(str, 0, sizeof(str));
   sprintf(str, "/%d.jpg",num);
}

/********推送图片*********/
static esp_err_t take_photo(int num) //将照片存储到sd卡中，从num开始命名 如：0.jpg
{
  camera_fb_t * fb = esp_camera_fb_get();
 //static int  num = 0;

     Serial.println("Taking picture...");

    if (!fb) {
      Serial.println("Camera capture failed");
      return ESP_FAIL;
    }
    else
      {
       
         //以下就是上一篇文章讲到的写入文件得到过程，但是一点点小区别
        fs::FS &fs = SD_MMC;
        //  Serial.printf("Writing file: %s\n", path);
       num_to_str(num,path);
         Serial.println(path);
        File file = fs.open(path, FILE_WRITE);
          if (!file) 
         {
           Serial.println("文件创建失败");
           }
         else
         {
           file.write(fb->buf , fb->len); //第一个参数是缓存，就是图片的存储地址，第二个参数是数据大小
           Serial.println("成功写入照片");
         
      
         //  num++;
           file.close();//一定要关闭文件
        }
        
         //return the frame buffer back to the driver for reuse
         esp_camera_fb_return(fb);//关闭fb
       }
  }
  
static esp_err_t send_photo(int num )//qu取出SD卡中名为num.jpg的图片并且发送出去
{
  ////////////////////////将sd卡图片数据提取到fb中//////////////////////////////////
   camera_fb_t * fb =esp_camera_fb_get(); 
   fb->len=0;
  *fb->buf=NULL;
       fs::FS &fs = SD_MMC;
       num_to_str(num,path);//文件名
         File file = fs.open(path,FILE_READ);
          if (!file) 
         {
           Serial.println("文件打开失败");
               file.close();
           }
         else
         {
         fb->len = file.size();//读取文件内大小
         file.read( fb->buf,  fb->len);//第一个参数是储存的buf，第二个是读取的信息长度
          file.close();
           Serial.println("成功读取照片");
        }

        ////////////////////网络申请，发出图片//////////////////////////////////
      HTTPClient http;
    //设置请求url
    http.begin(post_url);
    
    //设置请求头部信息
    http.addHeader("Content-Type", "image/jpg");
    http.addHeader("Authorization", uid);
    http.addHeader("Authtopic", topic);
    if(sentWechat){ //判断是否需要推送到微信
      http.addHeader("Wechatmsg", wechatMsg);  //设置 http 请求头部信息
    }
    //发起请求，并获取状态码
    int httpResponseCode = http.POST((uint8_t *)fb->buf,  fb->len);
    
    if(httpResponseCode==200){
        //获取post请求后的服务器响应信息，json格式
        String response = http.getString();  //Get the response to the request
        Serial.print("Response Msg:");
        Serial.println(response);           // 打印服务器返回的信息
        

        //json数据解析
        StaticJsonDocument<200> doc;
        DeserializationError error = deserializeJson(doc, response);
        if (error) {
          Serial.print(F("deserializeJson() failed: "));
          Serial.println(error.c_str());
        }
        const char* url = doc["url"];
        Serial.print("Get URL:");
        Serial.println(url);//打印获取的URL
    }else{
        //错误请求
        Serial.print("Error on sending POST: ");
        Serial.println(httpResponseCode);
    }

    Serial.print("HTTP Response code: ");
    Serial.println(httpResponseCode);
    //清空数据
    esp_camera_fb_return(fb);  
    //回收下次再用
    http.end();
  
  
  }
void setup()
{
  Serial.begin(115200);

  if (init_wifi()) { // Connected to WiFi
    internet_connected = true;
    Serial.println("Internet connected");
  }
  

  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
  //init with high specs to pre-allocate larger buffers
  if (psramFound()) {
    config.frame_size = FRAMESIZE_UXGA;
    config.jpeg_quality = 50;
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }


  // camera init
  esp_err_t err = esp_camera_init(&config);
  
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }
     sd_init();  //SD卡初始化

}


void loop()
{  
      take_photo(0);
      send_photo(0);

  
}
